package com.kyg.tjtoolmanager;

import com.kyg.tjtoolmanager.db.SQLiteUtils;
import com.kyg.tjtoolmanager.module.GlobalVariable;
import com.kyg.tjtoolmanager.module.WareHouse;
import com.kyg.tjtoolmanager.net.netty.init.StartNettyThread;
import com.kyg.tjtoolmanager.ui.StageFactory;
import com.kyg.tjtoolmanager.ui.StageUIHelper;
import com.kyg.tjtoolmanager.utils.SpeechUtil;
import com.kyg.tjtoolmanager.utils.Utils;
import io.netty.util.internal.StringUtil;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;

public class App extends Application {

    public static boolean DEBUG = false;
    public static boolean NettyStart = false;
    public static boolean StartFaceLogin = false;
    public static GlobalVariable globalVal;
    public static String icon_launcher = "drawable/ic_launcher.png";
    public static List<WareHouse> wareHouses = new ArrayList<>();

    private static final int SINGLE_INSTANCE_LISTENER_PORT = 9999;
    private static final String SINGLE_INSTANCE_FOCUS_MESSAGE = "focus";

    private static final String instanceId = UUID.randomUUID().toString();

    // We define a pause before focusing on an existing instance
    // because sometimes the command line or window launching the instance
    // might take focus back after the second instance execution complete
    // so we introduce a slight delay before focusing on the original window
    // so that the original window can retain focus.
    private static final int FOCUS_REQUEST_PAUSE_MILLIS = 500;

    private Stage stage;

    @Override
    public void init() throws Exception {
        super.init();
        try {
            SQLiteUtils.initDBTable();
        } catch (Exception ex) {
            StageUIHelper.getInstance().showTipAlert(ex.getMessage());
        }
        if (App.globalVal == null) {
            App.globalVal = new GlobalVariable();
        }

        CountDownLatch instanceCheckLatch = new CountDownLatch(1);
        Thread instanceListener = new Thread(() -> {
            try (ServerSocket serverSocket = new ServerSocket(SINGLE_INSTANCE_LISTENER_PORT, 10)) {
                instanceCheckLatch.countDown();

                while (true) {
                    try (
                            Socket clientSocket = serverSocket.accept();
                            BufferedReader in = new BufferedReader(
                                    new InputStreamReader(clientSocket.getInputStream()))
                    ) {
                        String input = in.readLine();
                        SQLiteUtils.insertLog("Received single instance listener message: " + input);
                        if (input.startsWith(SINGLE_INSTANCE_FOCUS_MESSAGE) && stage != null) {
                            Thread.sleep(FOCUS_REQUEST_PAUSE_MILLIS);
                            Platform.runLater(() -> {
                                SQLiteUtils.insertLog("To front " + instanceId);
                                stage.setIconified(false);
                                stage.show();
                                stage.toFront();
                            });
                        }
                    } catch (IOException e) {
                        SQLiteUtils.insertLog("Single instance listener unable to process focus message from client");
                        e.printStackTrace();
                    }
                }
            } catch (java.net.BindException b) {
                SQLiteUtils.insertLog("SingleInstanceApp already running");

                try (
                        Socket clientSocket = new Socket(Utils.getLocalIP(), SINGLE_INSTANCE_LISTENER_PORT);
                        PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()))
                ) {
                    SQLiteUtils.insertLog("Requesting existing app to focus");
                    out.println(SINGLE_INSTANCE_FOCUS_MESSAGE + " requested by " + instanceId);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                SQLiteUtils.insertLog("Aborting execution for instance " + instanceId);
                Platform.exit();
            } catch (Exception e) {
                SQLiteUtils.insertLog(e.toString());
            } finally {
                instanceCheckLatch.countDown();
            }
        }, "instance-listener");
        instanceListener.setDaemon(true);
        instanceListener.start();

        try {
            instanceCheckLatch.await();
        } catch (InterruptedException e) {
            Thread.interrupted();
        }
    }

    @Override
    public void start(Stage stage) throws IOException {
        this.stage = stage;
        Platform.setImplicitExit(false);
        String fxml = "main-view.fxml";
//        StageUIHelper.toCustomUI("工具管理系统", "main-view.fxml", new EventHandler<WindowEvent>() {
//            @Override
//            public void handle(WindowEvent windowEvent) {
//                SQLiteUtils.closeConnection();
//            }
//        });
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml));
        Scene scene = new Scene(fxmlLoader.load());
        stage.setTitle("工具管理系统");
//        fxmlLoader.setControllerFactory(new Callback<Class<?>, Object>() {
//        });
//        stage.setAlwaysOnTop(true);
//        stage.setFullScreen(true);
        Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
        int width = (int) (bounds.getWidth() * 0.5);
        int height = (int) (bounds.getHeight() * 0.5);
        stage.setWidth(width);
        stage.setHeight(width);
//        stage.setMaximized(true); //最大化
        stage.setResizable(false);
        stage.getIcons().add(new Image(App.class.getResourceAsStream(App.icon_launcher)));
//        stage.initModality(Modality.WINDOW_MODAL);
        stage.setScene(scene);
        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent windowEvent) {
                SQLiteUtils.closeConnection();
            }
        });
        stage.show();
        StageFactory.dispatchStageShowed(fxml);

        SpeechUtil.textToSpeech("欢迎使用");

        if (!StringUtil.isNullOrEmpty(App.globalVal.nettyPort)) {
            StartNettyThread startNettyThread = new StartNettyThread();
            startNettyThread.setIsKeepHttpConnectionPort(Integer.parseInt(App.globalVal.nettyPort));
            startNettyThread.start();
        }
    }

    public static void main(String[] args) {
        launch();
    }

}